package com.sfang.common.redis;


import com.alibaba.fastjson.JSON;
import com.sfang.common.redis.annotations.ExpireSecond;
import com.sfang.common.redis.enums.CacheType;
import com.sfang.common.redis.sdk.RedisClient;
import com.sfang.common.redis.sdk.RedisLock;
import com.sfang.common.redis.sdk.RedisScript;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import reactor.util.function.Tuple2;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * Created by psalmody on 2016/8/7.
 */
@Component
@Order(1)
public class Cache {

    private static RedisClient cacheService;
    private static Logger LOGGER = LoggerFactory.getLogger(Cache.class);

    @Autowired
    private RedisClient redisClient;

    @PostConstruct
    public void init() {
        this.cacheService = redisClient;
    }

    private static ConcurrentHashMap<Integer, Integer> _dicReflectedExpireSecond = new ConcurrentHashMap<Integer, Integer>();
    private static final Object _lockObject = new Object();//安全锁定

    //根据CacheType去获取值
    public static <T> T get(CacheType cacheType) {
        return (T) cacheService.getBucket(cacheType.identifier()).get();
    }

    public static <T> T getTtl(String key) {
        return (T) cacheService.getBucket(key).getTtl();
    }

    //根据CacheType和key去获取值
    public static <T> T get(CacheType cacheType, String key) {
        return (T) cacheService.getBucket(cacheType.identifier() + key).get();
    }

    //根据CacheType去获取值，如果值不存在，则调用supplier返回的值去设置value值并返回
    public static <T> T get(CacheType cacheType, Supplier<T> supplier) {
        try {
            T t = (T) cacheService.getBucket(cacheType.identifier()).get();

            if (t == null) {
                t = supplier.get();

                if (t == null)
                    return t;

                if (t instanceof List && ((List) t).size() == 0)
                    return t;

                int expireDuration = getExpireSecond(cacheType);

                if (expireDuration > -1)
                    cacheService.getBucket(cacheType.identifier()).set(t, expireDuration, TimeUnit.SECONDS);
                else
                    cacheService.getBucket(cacheType.identifier()).set(t);
            }
            return t;

        } catch (Exception e) {
            LOGGER.error(JSON.toJSONString(e));
            return supplier.get();
        }

    }

    //根据CacheType和key去获取值，如果值不存在，则调用supplier返回的值去设置value值并返回
    public static <T> T get(CacheType cacheType, String key, Supplier<T> supplier) {
        try {
            T t = (T) cacheService.getBucket(cacheType.identifier() + key).get();

            if (t == null) {
                t = supplier.get();

                if (t == null)
                    return t;

                if (t instanceof List && ((List) t).size() == 0)
                    return t;

                int expireDuration = getExpireSecond(cacheType);

                if (expireDuration > -1)
                    cacheService.getBucket(cacheType.identifier() + key).set(t, expireDuration, TimeUnit.SECONDS);
                else
                    cacheService.getBucket(cacheType.identifier() + key).set(t);
            }

            return t;
        } catch (Exception e) {
            LOGGER.error(JSON.toJSONString(e));
            return supplier.get();
        }
    }

    public static <T> T get(String key) {
        try {
            return (T) cacheService.getBucket(key).get();
        } catch (Exception e) {
            return null;
        }
    }

    //根据CacheType将值设置为value值
    public static <T> void set(CacheType cacheType, T value) {
        try {
            int expireDuration = getExpireSecond(cacheType);

            if (expireDuration == -1)
                cacheService.getBucket(cacheType.identifier()).set(value);
            else
                cacheService.getBucket(cacheType.identifier()).set(value, expireDuration, TimeUnit.SECONDS);
        } catch (Exception e) {
            LOGGER.error(String.format("cache set error:", JSON.toJSONString(e)));
        }
    }

    //根据CacheType和key将值设置为value值
    public static <T> void set(CacheType cacheType, String key, T value) {
        try {
            int expireDuration = getExpireSecond(cacheType);

            if (expireDuration == -1)
                cacheService.getBucket(cacheType.identifier() + key).set(value);
            else
                cacheService.getBucket(cacheType.identifier() + key).set(value, expireDuration, TimeUnit.SECONDS);
        } catch (Exception e) {
            LOGGER.error("redis set异常：" + JSON.toJSONString(e));
        }
    }

    public static <T> void set(String key, T value) {
        try {
            cacheService.getBucket(key).set(value);
        } catch (Exception e) {
            LOGGER.error("redis set异常：" + JSON.toJSONString(e));
        }
    }

    public static <T> void set(String key, T value, long expireDuration, TimeUnit timeUnit) {
        try {
            cacheService.getBucket(key).set(value, expireDuration, timeUnit);
        } catch (Exception e) {
            LOGGER.error("redis set异常：" + JSON.toJSONString(e));
        }
    }

    //根据CacheType删除value值
    public static void delete(CacheType cacheType) {
        try {
            cacheService.getBucket(cacheType.identifier()).delete();
        } catch (Exception e) {
            LOGGER.error(String.format("cache delete error:", JSON.toJSONString(e)));
        }
    }

    //根据CacheType和key删除value值
    public static void delete(CacheType cachetype, String key) {
        try {
            cacheService.getBucket(cachetype.identifier() + key).delete();
        } catch (Exception e) {
            LOGGER.error("redis delete异常：" + JSON.toJSONString(e));
        }
    }

    public static void delete(String key) {
        try {
            cacheService.getBucket(key).delete();
        } catch (Exception e) {
            LOGGER.error("redis delete异常：" + JSON.toJSONString(e));
        }
    }

    //根据CacheType和key将值设置过期时间为seconds
    public static void expire(CacheType cacheType, String key, int seconds) {
        try {
            cacheService.getBucket(cacheType.identifier() + key).expire(seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            LOGGER.error(String.format("cache expire error:", JSON.toJSONString(e)));
        }
    }

    public static void expire(String key, long seconds, TimeUnit timeUnit) {
        try {
            cacheService.getBucket(key).expire(seconds, timeUnit);
        } catch (Exception e) {
            LOGGER.error(String.format("cache expire error:", JSON.toJSONString(e)));
        }
    }

    //根据CacheType将值设置过期时间为seconds
    public static void expire(CacheType cacheType, int seconds) {
        try {
            cacheService.getBucket(cacheType.identifier()).expire(seconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            LOGGER.error(String.format("cache expire error:", JSON.toJSONString(e)));
        }
    }

    //根据cacheType自增并返回值
    public static long increment(CacheType cacheType) {
        return cacheService.getAtomicLong(cacheType.identifier()).incrementAndGet();
    }

    public static long increment(CacheType cacheType, Integer value) {
        Long range = cacheService.getAtomicLong(cacheType.identifier()).getAndAdd(value);
        if (range != null)
            range = range + 1;

        return range;
    }

    public static long increment(CacheType cacheType, String key) {
        return cacheService.getAtomicLong(cacheType.identifier() + key).incrementAndGet();
    }

    public static long increment(String key) {
        return cacheService.getAtomicLong(key).incrementAndGet();
    }

    //计数跳跃
    public static long increment(String key, Integer value) {
        if (value == null) {
            return 0L;
        }
        cacheService.getAtomicLong(key).getAndAdd(value);
        return cacheService.getAtomicLong(key).get();
    }

    public static long decrement(CacheType cacheType, String key) {
        return cacheService.getAtomicLong(cacheType.identifier() + key).decrementAndGet();
    }

    //根据CacheType和key判断是否存在 true-存在 false-不存在
    public static boolean isExists(CacheType cacheType, String key) {
        try {
            return cacheService.getBucket(cacheType.identifier() + key).isExists();
        } catch (Exception e) {
            LOGGER.error("redis isExists异常：" + JSON.toJSONString(e));
            return false;
        }
    }

    //根据CacheType判断值是否存在 true-存在 false-不存在
    public static boolean isExists(CacheType cacheType) {
        try {
            return cacheService.getBucket(cacheType.identifier()).isExists();
        } catch (Exception e) {
            LOGGER.error("redis isExists异常：" + JSON.toJSONString(e));
            return false;
        }
    }

    public static boolean isExists(String key) {
        try {
            return cacheService.getBucket(key).isExists();
        } catch (Exception e) {
            LOGGER.error("redis isExists异常：" + JSON.toJSONString(e));
            return false;
        }
    }

    public static <K, V> V mapAdd(String mapKey, K entryKey, V value) {
        return (V) cacheService.getMap(mapKey).put(entryKey, value);
    }

    public static <K, V> V mapAdd(CacheType cacheType, K entryKey) {
        return (V) cacheService.getMap(cacheType.identifier()).put(entryKey, entryKey);
    }

    public static <K, V> V mapAdd(CacheType cacheType, K entryKey, V value) {
        return (V) cacheService.getMap(cacheType.identifier()).put(entryKey, value);
    }

    public static <K, V> V mapAdd(CacheType cacheType, String key, Tuple2<K, V> entry) {
        return (V) cacheService.getMap(cacheType.identifier() + key).put(entry.getT1(), entry.getT2());
    }

    public static <K, V> V mapAdd(CacheType cacheType, String key, K entryKey, V value) {
        return (V) cacheService.getMap(cacheType.identifier() + key).put(entryKey, value);
    }

    public static <K, V> V mapAdd(CacheType cacheType, Tuple2<K, V> entry) {
        return (V) cacheService.getMap(cacheType.identifier()).put(entry.getT1(), entry.getT2());
    }

    public static void mapAddAll(CacheType cacheType, String key, Map map) {
        cacheService.getMap(cacheType.identifier() + key).putAll(map);

        int expireDuration = getExpireSecond(cacheType);
        if (expireDuration > -1)
            cacheService.getMap(cacheType.identifier() + key).expire(expireDuration, TimeUnit.SECONDS);

    }

    public static void mapAddAll(CacheType cacheType, Map map) {
        cacheService.getMap(cacheType.identifier()).putAll(map);

        int expireDuration = getExpireSecond(cacheType);
        if (expireDuration > -1)
            cacheService.getMap(cacheType.identifier()).expire(expireDuration, TimeUnit.SECONDS);

    }

    public static void mapAddAll(String key, Map map) {
        cacheService.getMap(key).putAll(map);
    }

    public static void mapAddAll(String key, Map map, long expireDuration, TimeUnit timeUnit) {
        cacheService.getMap(key).putAll(map);
        cacheService.getMap(key).expire(expireDuration, timeUnit);
    }

    public static <K, V> Map<K, V> mapFindAll(CacheType cacheType, K key) {
        return (Map<K, V>) cacheService.getMap(cacheType.identifier() + key).readAllMap();
    }

    public static <K, V> Map<K, V> mapFindAll(CacheType cacheType) {
        return (Map<K, V>) cacheService.getMap(cacheType.identifier()).readAllMap();
    }

    public static <K, V> Map<K, V> mapFindAll(CacheType cacheType, Supplier<Map> supplier) {
        Map map = cacheService.getMap(cacheType.identifier()).readAllMap();

        if (map == null || map.size() == 0) {
            map = supplier.get();

            if (map == null || map.size() == 0)
                return map;

            cacheService.getMap(cacheType.identifier()).putAll(map);

            int expireDuration = getExpireSecond(cacheType);
            if (expireDuration > -1)
                cacheService.getMap(cacheType.identifier()).expire(expireDuration, TimeUnit.SECONDS);
        }

        return map;
    }

    public static <T> List mapFindByVal(CacheType cacheType, String value) {
        return cacheService.getMap(cacheType.identifier()).mapFindByVal(value);
    }

    public static Map mapFindAll(CacheType cacheType, String key, Supplier<Map> supplier) {
        try {
            Map map = cacheService.getMap(cacheType.identifier() + key).readAllMap();

            if (map == null || map.size() == 0) {
                map = supplier.get();

                if (map == null || map.size() == 0)
                    return map;

                cacheService.getMap(cacheType.identifier() + key).putAll(map);

                int expireDuration = getExpireSecond(cacheType);
                if (expireDuration > -1)
                    cacheService.getMap(cacheType.identifier() + key).expire(expireDuration, TimeUnit.SECONDS);

            }

            return map;
        } catch (Exception e) {
            LOGGER.error(JSON.toJSONString(e));
            return supplier.get();
        }

    }

    public static <K, V> Map<K, V> mapFindAll(String key) {
        try {
            return (Map<K, V>) cacheService.getMap(key).readAllMap();
        } catch (Exception e) {
            LOGGER.error(JSON.toJSONString(e));
            return new HashMap<>();
        }

    }

    public static <V> V mapFindEntry(CacheType cacheType, String key) {
        return (V) cacheService.getMap(cacheType.identifier()).get(key);
    }

    public static <V> V mapFindEntry(CacheType cacheType, Integer key) {
        return (V) cacheService.getMap(cacheType.identifier()).get(key);
    }

    public static <V> V mapFindEntry(CacheType cacheType, Long value) {
        Optional<Object> matched = cacheService.getMap(cacheType.identifier()).getKeySet()
                .stream().filter(key -> {
                    Tuple2<Long, Long> customKeyValuePair = (Tuple2<Long, Long>) key;
                    return customKeyValuePair.getT1() <= value && customKeyValuePair.getT2() >= value;
                }).findFirst();

        return matched.isPresent()
                ? (V) cacheService.getMap(cacheType.identifier()).get(matched.get())
                : null;

    }

    public static <K, V> V mapFindEntry(String mapKey, K key) {
        return (V) cacheService.getMap(mapKey).get(key);
    }

    public static <K, V> Map<K, V> mapFindEntries(CacheType cacheType, Set<Object> keys) {
        return (Map<K, V>) cacheService.getMap(cacheType.identifier()).getAll(keys);
    }

    public static <K, V> Map<K, V> mapFindEntries(CacheType cacheType, String key, Set<Object> keys) {
        return (Map<K, V>) cacheService.getMap(cacheType.identifier() + key).getAll(keys);
    }

    public static boolean mapIsExists(CacheType cacheType, String key) {
        return cacheService.getMap(cacheType.identifier() + key).isExists();
    }

    public static boolean mapIsExists(CacheType cacheType) {
        return cacheService.getMap(cacheType.identifier()).isExists();
    }

    public static <K> boolean mapIsExists(String key, K entryKey) {
        return Optional.of(cacheService.getMap(key)).map(m -> m.containsKey(entryKey)).orElse(false);
    }

    public static <K, V> boolean mapIsExists(CacheType cacheType, K entryKey) {
        return Optional.of(cacheService.getMap(cacheType.identifier())).map(m -> m.containsKey(entryKey))
                .orElse(false);
    }

    public static <K, V> V mapRemove(CacheType cacheType, K key) {
        return (V) cacheService.getMap(cacheType.identifier()).remove(key);
    }

    public static <K, V> V mapRemove(String mapKey, K key) {
        return (V) cacheService.getMap(mapKey).remove(key);
    }

    public static Set mapFindKeySet(CacheType cacheType) {
        return cacheService.getMap(cacheType.identifier()).getKeySet();
    }

    public static boolean mapDelete(String key) {
        return cacheService.getMap(key).delete();
    }

    public static <V> V mapRemoveEntry(CacheType cacheType, String key) {
        return (V) cacheService.getMap(cacheType.identifier()).remove(key);
    }

    public static <V> V mapRemoveEntry(CacheType cacheType, String key, String entryKey) {
        return (V) cacheService.getMap(cacheType.identifier() + key).remove(entryKey);
    }

    public static <V> V mapRemoveEntry(String key, String entryKey) {
        return (V) cacheService.getMap(key).remove(entryKey);
    }

    public static <V> V mapFindEntry(CacheType cacheType, String key, String entryKey) {
        return (V) cacheService.getMap(cacheType.identifier() + key).get(entryKey);
    }

    public static <V> void listAdd(CacheType cacheType, V v) {
        cacheService.getList(cacheType.identifier()).add(v);
    }

    public static <V> void listAdd(String redisKey, V v) {
        cacheService.getList(redisKey).add(v);
    }

    public static void listAddAll(CacheType cacheType, Collection values) {
        cacheService.getList(cacheType.identifier()).addAll(values);
    }

    public static void listAddAll(String listKey, List list) {
        cacheService.getList(listKey).addAll(list);
    }

    public static <V> void listLeftPush(String key, V v) {
        script("redis.call(\"LPUSH\",KEYS[1], ARGV[1])", key, v);
    }

    public static <V> void listRightPush(String key, V v) {
        script("redis.call(\"RPUSH\",KEYS[1], ARGV[1])", key, v);
    }

    public static <V> V listRightPop(String key) {
        return (V) cacheService.getList(key).rightPop();
    }

    public static <V> V listAll(String key) {
        return (V) cacheService.getList(key).readAll();
    }

    public static <V> void setAdd(CacheType cacheType, String key, V value) {
        cacheService.getSet(cacheType.identifier() + key).add(value);

        int expireDuration = getExpireSecond(cacheType);
        if (expireDuration > -1)
            cacheService.getSet(cacheType.identifier() + key).expire(expireDuration, TimeUnit.SECONDS);
    }

    public static <V> void setAdd(String key, V value) {
        cacheService.getSet(key).add(value);
    }

    public static void setAddAll(String key, Set value) {
        cacheService.getSet(key).addAll(value);
    }

    public static void setAddAll(CacheType cacheType, String key, List<Object> value) {
        cacheService.getSet(cacheType.identifier() + key).addAll(value);

        int expireDuration = getExpireSecond(cacheType);
        if (expireDuration > -1)
            cacheService.getSet(cacheType.identifier() + key).expire(expireDuration, TimeUnit.SECONDS);
    }

    public static void setClear(CacheType cacheType, String key) {
        cacheService.getSet(cacheType.identifier() + key).clear();
    }

    public static <V> boolean setRemove(CacheType cacheType, String key, V value) {
        return cacheService.getSet(cacheType.identifier() + key).remove(value);
    }

    public static <V> boolean setRemove(String key, V value) {
        return cacheService.getSet(key).remove(value);
    }

    public static <V> Integer setSize(CacheType cacheType, String key) {
        try {
            return cacheService.getSet(cacheType.identifier() + key).size();
        } catch (Exception e) {
            return 0;
        }
    }

    public static <V> Set<V> setFindAll(String key) {
        return (Set<V>) cacheService.getSet(key).readAll();
    }


    public static <V> Set<V> setFindAll(CacheType cacheType, String key) {
        return (Set<V>) cacheService.getSet(cacheType.identifier() + key).readAll();
    }

    public static Boolean tryLock(String key, long waitTime, long leaseTime, TimeUnit unit) throws
            InterruptedException {
        RedisLock lock = cacheService.getLock(String.valueOf(key));
        return lock.tryLock(waitTime, leaseTime, unit);
    }

    public static RedisLock getLock(String key) {
        return cacheService.getLock(String.valueOf(key));
    }

    public static void unlock(String key) {
        RedisLock lock = cacheService.getLock(String.valueOf(key));
        lock.unlock();
    }

    public static boolean isLocked(String key) {
        RedisLock lock = cacheService.getLock(String.valueOf(key));
        return lock.isLocked();
    }

    public static <K, V> Boolean tryLock(K key, V v, long expireDuration, TimeUnit timeUnit) {
        RedisLock lock = cacheService.getLock(String.valueOf(key));

        try {
            return lock.tryLock(expireDuration, timeUnit);
        } catch (InterruptedException e) {
            LOGGER.error(String.format("%s tryLock error:%s", String.valueOf(key), JSON.toJSON(e)));
            return false;
        }
    }

    public static <K, V> V tryLock(K key, V v, long expireDuration, TimeUnit timeUnit, Supplier<V> supplier) {

        String lockKey = key.toString();
        try {
            RedisLock lock = cacheService.getLock(lockKey);

            if (lock.tryLock(expireDuration, timeUnit)) {
                try {
                    LOGGER.warn(String.format("%s acquires the lock success", lockKey));
                    return supplier.get();
                } finally {
                    lock.unlock();
                    LOGGER.warn(String.format("%s unlock the lock success", lockKey));
                }
            } else {
                LOGGER.error(String.format("%s acquires the lock failed", lockKey));
                return null;
            }
        } catch (Exception e) {
            LOGGER.error(String.format("%s tryLock error:%s", lockKey, JSON.toJSON(e)));
            return null;
        }
    }

    public static <V> V tryLock(CacheType cacheType, String key, Supplier<V> supplier) {
        String lockKey = cacheType != null
                ? cacheType.identifier() + key
                : key;
        try {
            RedisLock lock = cacheService.getLock(lockKey);

            if (lock.tryLock()) {
                try {
                    LOGGER.warn(String.format("%s acquires the lock success", lockKey));
                    return supplier.get();
                } finally {
                    lock.unlock();
                    LOGGER.warn(String.format("%s unlock the lock success", lockKey));
                }
            } else {
                LOGGER.error(String.format("%s acquires the lock failed", lockKey));
                return null;
            }
        } catch (Exception e) {
            LOGGER.error(String.format("%s tryLock error:%s", lockKey, JSON.toJSON(e)));
            return null;
        }
    }

    public static <V> V tryLock(String key, Supplier<V> supplier) {
        try {
            RedisLock lock = cacheService.getLock(key);

            if (lock.tryLock()) {
                try {
                    LOGGER.warn(String.format("%s acquires the lock success", key));
                    return supplier.get();
                } finally {
                    lock.unlock();
                    LOGGER.warn(String.format("%s unlock the lock success", key));
                }
            } else {
                LOGGER.error(String.format("%s acquires the lock failed", key));
                return null;
            }
        } catch (Exception e) {
            LOGGER.error(String.format("%s tryLock error:%s", key, JSON.toJSON(e)));
            throw e;
        }
    }

    public static <V> V tryLock(CacheType cacheType, String key, long mmillisecond, Supplier<V> supplier) {
        try {
            RedisLock lock = cacheService.getLock(cacheType.identifier() + key);

            try {
                if (lock.tryLock(mmillisecond, TimeUnit.MILLISECONDS)) {
                    try {
                        LOGGER.warn(String.format("%s acquires the lock success", cacheType.identifier() + key));
                        return supplier.get();
                    } finally {
                        lock.unlock();
                        LOGGER.warn(String.format("%s unlock the lock success", cacheType.identifier() + key));
                    }
                } else {
                    LOGGER.warn(String.format("%s acquires the lock failed", cacheType.identifier() + key));
                    return null;
                }
            } catch (InterruptedException e) {
                return null;
            }
        } catch (Exception e) {
            LOGGER.error(String.format("%s tryLock error:%s", cacheType.identifier() + key, JSON.toJSON(e)));
            return supplier.get();
        }
    }

    public static <V> V tryLockWithDefault(CacheType cacheType, String key, long mmillisecond, Supplier<
            V> supplier,
                                           Supplier<V> lockFailed) {
        try {
            RedisLock lock = cacheService.getLock(cacheType.identifier() + key);

            if (lock.tryLock(mmillisecond, TimeUnit.MILLISECONDS)) {
                try {
                    LOGGER.warn(String.format("%s acquires the lock success", cacheType.identifier() + key));
                    return supplier.get();
                } finally {
                    lock.unlock();
                    LOGGER.warn(String.format("%s unlock the lock success", cacheType.identifier() + key));
                }
            } else {
                LOGGER.error(String.format("%s acquires the lock failed", cacheType.identifier() + key));
                return lockFailed.get();
            }
        } catch (Exception e) {
            LOGGER.error(String.format("%s tryLock error:%s", cacheType.identifier() + key, JSON.toJSON(e)));
            return lockFailed.get();
        }
    }

    public <T> void addDelayQueue(T value, long delay, String queueCode) {
        cacheService.addDelayQueue(value, delay, queueCode);
    }

    public static List<String> getKeysByPattern(String pattern) {
        return cacheService.keys(pattern);
    }

    private static int getExpireSecond(CacheType cachetype) {

        if (_dicReflectedExpireSecond.containsKey(cachetype.sequence())) {
            return _dicReflectedExpireSecond.get(cachetype.sequence());
        }

        synchronized (_lockObject) {
            try {
                int result = -1;
                Field field = cachetype.getClass().getDeclaredField(cachetype.identifierExcludeNamespace());

                if (field.isAnnotationPresent(ExpireSecond.class)) {
                    ExpireSecond expireSecond = (ExpireSecond) field.getAnnotation(ExpireSecond.class);
                    result = expireSecond.value();
                }

                _dicReflectedExpireSecond.put(Integer.valueOf(cachetype.sequence()), result);

                return result;
            } catch (Exception e) {
                return -1;
            }
        }
    }

    private static <V> V script(String script, String key, V value) {

        try {
            RedisScript rScript = cacheService.getScript();
            return (V) rScript.eval(script, key, value);
        } catch (Exception e) {
            LOGGER.error(String.format("%s script error:%s", key, JSON.toJSON(e)));
            return null;
        }
    }
}
